home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / debugger / ddd-1.000 / ddd-1 / ddd-1.4b / libiberty / mpw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-12  |  40.8 KB  |  1,819 lines

  1. /* MPW-Unix compatibility library.
  2.    Copyright (C) 1993, 1994 Free Software Foundation, Inc.
  3.  
  4. This file is part of the libiberty library.
  5. Libiberty is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Library General Public
  7. License as published by the Free Software Foundation; either
  8. version 2 of the License, or (at your option) any later version.
  9.  
  10. Libiberty is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13. Library General Public License for more details.
  14.  
  15. You should have received a copy of the GNU Library General Public
  16. License along with libiberty; see the file COPYING.LIB.  If
  17. not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  18. Boston, MA 02111-1307, USA.  */
  19.  
  20. /* This should only be compiled and linked under MPW. */
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <files.h>
  25. #include <ioctl.h>
  26. #include <ioctl.h>
  27. #include <fcntl.h>
  28. #include <errno.h>
  29.  
  30. #include <sys/stat.h>
  31. #include <sys/time.h>
  32. #include <sys/resource.h>
  33.  
  34. #include <Types.h>
  35.  
  36. #include <spin.h>
  37.  
  38. #ifndef R_OK
  39. #define R_OK 4
  40. #define W_OK 2
  41. #define X_OK 1
  42. #endif
  43.  
  44. #define ENOSYS 99
  45.  
  46. extern int errno;
  47.  
  48. #ifndef IN_GCC
  49.  
  50. extern int sys_nerr;
  51.  
  52. extern char **sys_errlist;
  53.  
  54. #endif
  55.  
  56. int DebugPI = 0;
  57.  
  58. void mpw_abort (void);
  59.  
  60. void
  61. mpwify_filename(char *unixname, char *macname)
  62. {
  63.   int i, j, in_middle, terminate = 0;
  64.  
  65.   /* (should truncate 255 chars from end of name, not beginning) */
  66.   if (strlen (unixname) > 255)
  67.     {
  68.       fprintf (stderr, "Pathname \"%s\" is too long for Macs, truncating\n",
  69.            unixname);
  70.       terminate = 1;
  71.     }
  72.   /* Abs Unix path to abs Mac path. */
  73.   if (*unixname == '/')
  74.     {
  75.       if (strncmp (unixname, "/tmp/", 6) == 0)
  76.     {
  77.       /* A temporary name, make a more Mac-flavored tmpname. */
  78.       /* A better choice would be {Boot}Trash:foo, but that would
  79.          require being able to identify the boot disk's and trashcan's
  80.          name.  Another option would be to have an env var, so user
  81.          can point it at a ramdisk. */
  82.       strncpy (macname, unixname, 255);
  83.       if (terminate)
  84.         macname[255] = '\0';
  85.       macname[0] = ':';
  86.       macname[4] = '_';
  87.     }
  88.       else
  89.     {
  90.       /* Assume that the leading component is a valid disk name. */
  91.       strncpy (macname, unixname + 1, 255);
  92.     }
  93.     }
  94.   else
  95.     {
  96.       /* If this is a "Unix-only" pathname, assume relative. */
  97.       if (strchr (unixname, '/') && ! strchr (unixname, ':'))
  98.     {
  99.       macname[0] = ':';
  100.       strncpy (macname + 1, unixname, 255);
  101.     }
  102.       else
  103.     {
  104.       /* Otherwise copy it verbatim. */
  105.       /* ... but if of the form ":/foo", lose the extra colon;
  106.          the slash will be made into a colon shortly. */
  107.       if (unixname[0] == ':' && unixname[1] == '/')
  108.         ++unixname;
  109.       strncpy (macname, unixname, 255);
  110.     }
  111.     }
  112.   if (terminate)
  113.     macname[255] = '\0';
  114.   for (i = 0; macname[i] != '\0'; ++i)
  115.     {
  116.       if (macname[i] == '/')
  117.     macname[i] = ':';
  118.     }
  119.   in_middle = 0;
  120.   j = 0;
  121.   for (i = 0; macname[i] != '\0'; ++i)
  122.     {
  123.       /* We're in the middle of the name when a char is not a colon. */
  124.       if (macname[i] != ':')
  125.     in_middle = 1;
  126.       /* Copy chars verbatim, *unless* the char is the first of a pair
  127.      of colons in the middle of a pathname. */
  128.       if (!(in_middle && macname[i] == ':' && macname[i+1] == ':'))
  129.     macname[j++] = macname[i];
  130.     }
  131.   macname[j] = '\0';
  132.   /* If we have a trailing ":.", make it into a ":". */
  133.   if (j >= 2 && macname[j-2] == ':' && macname[j-1] == '.')
  134.     macname[j-1] = '\0';
  135.   if (DebugPI)
  136.     {
  137.       fprintf (stderr, "# Made \"%s\"\n", unixname);
  138.       fprintf (stderr, "# into \"%s\"\n", macname);
  139.     }
  140. }
  141.  
  142. /* MPW-flavored basename finder. */
  143.  
  144. char *
  145. mpw_basename (name)
  146.   char *name;
  147. {
  148.   char *base = name;
  149.  
  150.   while (*name)
  151.     {
  152.       if (*name++ == ':')
  153.     {
  154.       base = name;
  155.     }
  156.     }
  157.   return base;
  158. }
  159.  
  160. /* Mixed MPW/Unix basename finder.  This can be led astray by
  161.    filenames with slashes in them and come up with a basename that
  162.    either corresponds to no file or (worse) to some other file, so
  163.    should only be tried if other methods of finding a file via a
  164.    basename have failed.  */
  165.  
  166. char *
  167. mpw_mixed_basename (name)
  168.   char *name;
  169. {
  170.   char *base = name;
  171.  
  172.   while (*name)
  173.     {
  174.       if (*name == '/' || *name == ':')
  175.     {
  176.       base = name + 1;
  177.     }
  178.       ++name;
  179.     }
  180.   return base;
  181. }
  182.  
  183. /* This function is fopen() modified to create files that are type TEXT
  184.    or 'BIN ', and always of type 'MPS '.  */
  185.  
  186. FILE *
  187. mpw_fopen (char *name, char *mode)
  188. {
  189. #undef fopen
  190.   int errnum;
  191.   FILE *fp;
  192.   char tmpname[256];
  193.  
  194.   mpwify_filename (name, tmpname);
  195.   PROGRESS (1);
  196.   fp = fopen (tmpname, mode);
  197.   errnum = errno;
  198.  
  199.   /* If writing, need to set type and creator usefully. */
  200.   if (strchr (mode, 'w'))
  201.     {
  202.       char *pname = (char *) malloc (strlen (tmpname) + 2);
  203.       OSErr e;
  204.       struct FInfo fi;
  205.  
  206.       pname[0] = strlen (tmpname);
  207.       strcpy (pname+1, tmpname);
  208.     
  209.       e = GetFInfo (pname, 0, &fi);
  210.       /* should do spiffier error handling */
  211.       if (e != 0)
  212.     fprintf(stderr, "GetFInfo returns %d\n", e);
  213.       if (strchr (mode, 'b'))
  214.     {
  215.       fi.fdType = (OSType) 'BIN ';
  216.     }
  217.       else
  218.     {
  219.       fi.fdType = (OSType) 'TEXT';
  220.     }
  221.       fi.fdCreator = (OSType) 'MPS ';
  222.       e = SetFInfo (pname, 0, &fi);
  223.       if (e != 0)
  224.     fprintf(stderr, "SetFInfo returns %d\n", e);
  225.       free (pname);
  226.     }
  227.   if (fp == NULL)
  228.     errno = errnum;
  229.   return fp;
  230. }
  231.  
  232. /* This is a version of fseek() modified to fill the file with zeros
  233.    if seeking past the end of it.  */
  234.  
  235. #define ZEROBLKSIZE 4096
  236.  
  237. char zeros[ZEROBLKSIZE];
  238.  
  239. int
  240. mpw_fseek (FILE *fp, int offset, int whence)
  241. {
  242.   int cursize, numleft;
  243.  
  244.   PROGRESS (1);
  245.   if (whence == SEEK_SET)
  246.     {
  247.       fseek (fp, 0, SEEK_END);
  248.       cursize = ftell (fp);
  249.       if (offset > cursize)
  250.     {
  251.       numleft = offset - cursize;
  252.       while (numleft > ZEROBLKSIZE)
  253.         {
  254.           /* This might fail, should check for that. */
  255.           PROGRESS (1);
  256.           fwrite (zeros, 1, ZEROBLKSIZE, fp);
  257.           numleft -= ZEROBLKSIZE;
  258.         }
  259.       PROGRESS (1);
  260.       fwrite (zeros, 1, numleft, fp);
  261.       fflush (fp);
  262.     }
  263.     }
  264.   return fseek (fp, offset, whence);
  265. }
  266.  
  267. int
  268. mpw_fread (char *ptr, int size, int nitems, FILE *stream)
  269. {
  270. #undef fread
  271.   int rslt;
  272.  
  273.   PROGRESS (1);
  274.   rslt = fread (ptr, size, nitems, stream);
  275.   PROGRESS (1);
  276.   return rslt;
  277. }
  278.  
  279. int
  280. mpw_fwrite (char *ptr, int size, int nitems, FILE *stream)
  281. {
  282. #undef fwrite
  283.   int rslt;
  284.  
  285.   PROGRESS (1);
  286.   rslt = fwrite (ptr, size, nitems, stream);
  287.   PROGRESS (1);
  288.   return rslt;
  289. }
  290.  
  291. int
  292. fork ()
  293. {
  294.   fprintf (stderr, "fork not available!\n");
  295.   mpw_abort ();
  296. }
  297.  
  298. int
  299. vfork ()
  300. {
  301.   fprintf (stderr, "vfork not available!\n");
  302.   mpw_abort ();
  303.   return (-1);
  304. }
  305.  
  306. int
  307. pipe (int *fd)
  308. {
  309.   fprintf (stderr, "pipe not available!\n");
  310.   mpw_abort ();
  311.   return (-1);
  312. }
  313.  
  314. int
  315. execvp (char *file, char **argv)
  316. {
  317.   fprintf (stderr, "execvp not available!\n");
  318.   mpw_abort ();
  319.   return (-1);
  320. }
  321.  
  322. int
  323. execv (char *path, char **argv)
  324. {
  325.   fprintf (stderr, "execv not available!\n");
  326.   mpw_abort ();
  327.   return (-1);
  328. }
  329.  
  330. int
  331. kill (int pid, int sig)
  332. {
  333.   fprintf (stderr, "kill not available!\n");
  334.   mpw_abort ();
  335.   return (-1);
  336. }
  337.  
  338. int
  339. wait (int *status)
  340. {
  341.   *status = 0;
  342.   return 0;
  343. }
  344.  
  345. int
  346. sleep (int seconds)
  347. {
  348.   unsigned long start_time, now;
  349.  
  350.   time (&start_time);
  351.  
  352.   while (1)
  353.     {
  354.       PROGRESS (1);
  355.       time (&now);
  356.       if (now > start_time + seconds)
  357.     return 0;
  358.     }
  359. }
  360.  
  361. void
  362. putenv (char *str)
  363. {
  364.   /* The GCC driver calls this to do things for collect2, but we
  365.      don't care about collect2. */
  366. }
  367.  
  368. int
  369. chmod (char *path, int mode)
  370. {
  371.   /* Pretend it was all OK. */
  372.   return 0;
  373. }
  374.  
  375. int
  376. getuid ()
  377. {
  378.   /* One value is as good as another... */
  379.   return 0;
  380. }
  381.  
  382. int
  383. getgid ()
  384. {
  385.   /* One value is as good as another... */
  386.   return 0;
  387. }
  388.  
  389. /* Instead of coredumping, which is not a normal Mac facility, we
  390.    drop into Macsbug.  If we then "g" from Macsbug, the program will
  391.    exit cleanly. */
  392.  
  393. void
  394. mpw_abort ()
  395. {
  396.   /* Make sure no output still buffered up, then zap into MacsBug. */
  397.   fflush(stdout);
  398.   fflush(stderr);
  399.   printf("## Abort! ##\n");
  400. #ifdef MPW_SADE
  401.   SysError(8005);
  402. #else 
  403.   Debugger();
  404. #endif
  405.   /* "g" in MacsBug will then cause a regular error exit. */
  406.   exit (1);
  407. }
  408.  
  409. /* Imitation getrusage based on the ANSI clock() function. */
  410.  
  411. int
  412. getrusage (int who, struct rusage *rusage)
  413. {
  414.   int clk = clock ();
  415.  
  416.   rusage->ru_utime.tv_sec = clk / CLOCKS_PER_SEC;
  417.   rusage->ru_utime.tv_usec = ((clk * 1000) / CLOCKS_PER_SEC) * 1000;
  418.   rusage->ru_stime.tv_sec = 0;
  419.   rusage->ru_stime.tv_usec = 0;
  420. }
  421.  
  422. int
  423. sbrk ()
  424. {
  425.   return 0;
  426. }
  427.  
  428. char **environ = NULL;
  429.  
  430. int
  431. isatty (int fd)
  432. {
  433.   return 0;
  434. }
  435.  
  436. /* link.c  --  Un*x like function to hard link one file to another.
  437.  *          by  ||ugh Daniel <hugh@cygnus.com> 1994/1/3  */
  438.  
  439. /*
  440.  *  We have two choices here, make an Alias or duplacate the file.
  441.  * The only place I see this being used unlinks the orignal file right
  442.  * after makeing the link, so I think we copy the file.
  443.  *
  444.  *  We presume that we are copying a Mac style file (as it might be a
  445.  * mac binary executable), so we use funney Macintosh style functions
  446.  * insted of fopen() or something.
  447.  *
  448.  */
  449.  
  450. int link (char *path1, char *path2)
  451. {
  452. #ifdef    never
  453.   OSErr macretval;
  454.   HParamBlockRec workorder;
  455.  
  456.   workorder = (HParamBlockRec) malloc(sizeof(union HParamBlockRec));
  457.   workorder->CopyParam.
  458.     macretval = PBHCopyFile(workorder, false);
  459.   if ( macretval ) {
  460.   }
  461. #else  /* never */
  462.   return (-1);  /* link does not fit the macintosh file system model */
  463. #endif /* never */
  464. }
  465.  
  466. /* This is inherited from Timothy Murray's Posix library. */
  467.  
  468. #include "utime.h"
  469.  
  470. int
  471. utime (char *filename, struct utimbuf *times)
  472. {
  473.   CInfoPBRec cipbr;
  474.   HFileInfo *fpb = (HFileInfo *) &cipbr;
  475.   DirInfo *dpb = (DirInfo *) &cipbr;
  476.   unsigned char pname[256];
  477.   short err;
  478.   
  479.   strcpy ((char *) pname, filename);
  480.   c2pstr (pname);
  481.  
  482.   dpb->ioDrDirID = 0L;
  483.   fpb->ioNamePtr = pname;
  484.   fpb->ioVRefNum = 0;
  485.   fpb->ioFDirIndex = 0;
  486.   fpb->ioFVersNum = 0;
  487.   err = PBGetCatInfo (&cipbr, 0);
  488.   if (err != noErr) {
  489.     errno = ENOENT;
  490.     return -1;
  491.   }
  492.   dpb->ioDrDirID = 0L;
  493.   fpb->ioFlMdDat = times->modtime;
  494.   fpb->ioFlCrDat = times->actime;
  495.   err = PBSetCatInfo (&cipbr, 0);
  496.   if (err != noErr) {
  497.     errno = EACCES;
  498.     return -1;
  499.   }
  500.   return 0;
  501. }
  502.  
  503. int
  504. mkdir (char *path, int mode)
  505. {
  506.   errno = ENOSYS;
  507.   return -1;
  508. }
  509.  
  510. int
  511. rmdir ()
  512. {
  513.   errno = ENOSYS;
  514.   return -1;
  515. }
  516.  
  517. chown ()
  518. {
  519.   errno = ENOSYS;
  520.   return -1;
  521. }
  522.  
  523. /* Minimal 'stat' emulation: tells directories from files and
  524.    gives length and mtime.
  525.  
  526.    Derived from code written by Guido van Rossum, CWI, Amsterdam
  527.    and placed by him in the public domain.  */
  528.  
  529. char *myenviron[] = {NULL};
  530.  
  531. char **environ = myenviron;
  532.  
  533. extern int __uid, __gid;
  534.  
  535. int __uid = 0;
  536. int __gid = 0;
  537.  
  538. /* Bits in ioFlAttrib: */
  539. #define LOCKBIT    (1<<0)        /* File locked */
  540. #define DIRBIT    (1<<4)        /* It's a directory */
  541.  
  542. /* Macified "stat" in which filename is given relative to a directory,
  543.    specified by long DirID.  */
  544.  
  545. static int
  546. _stat (char *name, long dirid, struct stat *buf)
  547. {
  548.   CInfoPBRec cipbr;
  549.   HFileInfo *fpb = (HFileInfo*) &cipbr;
  550.   DirInfo *dpb = (DirInfo*) &cipbr;
  551.   Str255 pname;
  552.   short err;
  553.  
  554.   /* Make a temp copy of the name and pascalize. */
  555.   strcpy ((char *) pname, name);
  556.   c2pstr (pname);
  557.   
  558.   cipbr.dirInfo.ioDrDirID = dirid;
  559.   cipbr.hFileInfo.ioNamePtr = pname;
  560.   cipbr.hFileInfo.ioVRefNum = 0;
  561.   cipbr.hFileInfo.ioFDirIndex = 0;
  562.   cipbr.hFileInfo.ioFVersNum = 0;
  563.   err = PBGetCatInfo (&cipbr, 0);
  564.   if (err != noErr)
  565.     {
  566.       errno = ENOENT;
  567.       return -1;
  568.     }
  569.   /* Mac files are readable if they can be accessed at all. */
  570.   buf->st_mode = 0444;
  571.   /* Mark unlocked files as writeable. */
  572.   if (!(fpb->ioFlAttrib & LOCKBIT))
  573.     buf->st_mode |= 0222;
  574.   if (fpb->ioFlAttrib & DIRBIT)
  575.     {
  576.       /* Mark directories as "executable". */
  577.       buf->st_mode |= 0111 | S_IFDIR;
  578.       buf->st_size = dpb->ioDrNmFls;
  579.       buf->st_rsize = 0;
  580.     }
  581.   else
  582.     {
  583.       buf->st_mode |= S_IFREG;
  584.       /* Mark apps as "executable". */
  585.       if (fpb->ioFlFndrInfo.fdType == 'APPL')
  586.     buf->st_mode |= 0111;
  587.       /* Fill in the sizes of data and resource forks. */
  588.       buf->st_size = fpb->ioFlLgLen;
  589.       buf->st_rsize = fpb->ioFlRLgLen;
  590.     }
  591.   /* Fill in various times. */
  592.   buf->st_atime = fpb->ioFlCrDat;
  593.   buf->st_mtime = fpb->ioFlMdDat;
  594.   buf->st_ctime = fpb->ioFlCrDat;
  595.   /* Set up an imitation inode number. */
  596.   buf->st_ino = (unsigned short) fpb->ioDirID;
  597.   /* Set up an imitation device. */
  598.   GetVRefNum (buf->st_ino, &buf->st_dev);
  599.   buf->st_uid = __uid;
  600.   buf->st_gid = __gid;
  601. /*  buf->st_FlFndrInfo = fpb->ioFlFndrInfo;  */
  602.   return 0;
  603. }
  604.  
  605. /* stat() sets up an empty dirid. */
  606.  
  607. int
  608. stat (char *path, struct stat *buf)
  609. {
  610.   long rslt, errnum;
  611.   char tmpname[256];
  612.  
  613.   mpwify_filename (path, tmpname);
  614.   if (DebugPI)
  615.     fprintf (stderr, "# stat (%s, %x)", tmpname, buf);
  616.   PROGRESS (1);
  617.   rslt = _stat (tmpname, 0L, buf);
  618.   errnum = errno;
  619.   if (DebugPI)
  620.     {
  621.       fprintf (stderr, " -> %d", rslt);
  622.       if (rslt != 0)
  623.     fprintf (stderr, " (errno is %d)", errnum);
  624.       fprintf (stderr, "\n");
  625.       fflush (stderr);
  626.     }
  627.   if (rslt != 0)
  628.     errno = errnum;
  629.   return rslt;
  630. }
  631.  
  632. int
  633. fstat (int fd, struct stat *buf)
  634. {
  635.   FCBPBRec fcb;
  636.   Str255 pathname;
  637.   long dirid = 0L, temp;
  638.   long rslt, errnum;
  639.   short err;
  640.  
  641.   if (DebugPI)
  642.     fprintf (stderr, "# fstat (%d, %x)", fd, buf);
  643.   PROGRESS (1);
  644. #if 0
  645.   /* fdopen() gives FILE entry with name of file, as well as RefNum
  646.      of containing directory. */
  647.     
  648. /*  FILE *fp = fdopen(fd, "");  */
  649.   
  650.   /* Use PBGetFCBInfo() to convert short RefNum to long dirid. */
  651.  
  652.   ioctl (fd, FIOREFNUM, &temp);
  653.   fcb.ioRefNum = temp;
  654. #if 0
  655.   fcb.ioRefNum = fp->refnum;
  656. #endif
  657.   fcb.ioVRefNum = 0;
  658.   fcb.ioFCBIndx = 0;
  659.   fcb.ioNamePtr = pathname;
  660.   err = PBGetFCBInfo (&fcb, 0);
  661.   if (0 /*err != noErr*/)
  662.     {
  663.       errnum = ENOENT;
  664.       rslt = -1;
  665.     }
  666. #endif
  667.   dirid = 0L /* fcb.ioFCBParID */ ;
  668.   ioctl (fd, FIOFNAME, (long *) pathname); 
  669.   if (DebugPI)
  670.     fprintf (stderr, " (name is %s)", pathname);
  671.   rslt = _stat ((char *) pathname, dirid, buf);
  672.   errnum = errno;
  673.   if (DebugPI)
  674.     {
  675.       fprintf (stderr, " -> %d", rslt);
  676.       if (rslt != 0)
  677.     fprintf (stderr, " (errno is %d)", errnum);
  678.       fprintf (stderr, "\n");
  679.       fflush (stderr);
  680.     }
  681.   if (rslt != 0)
  682.     errno = errnum;
  683.   return rslt;
  684. }
  685.  
  686. /* This should probably be more elaborate for MPW. */
  687.  
  688. char *
  689. getpwd ()
  690. {
  691.   return ":";
  692. }
  693.  
  694. int
  695. mpw_open (char *filename, int arg2, int arg3)
  696. {
  697. #undef open
  698.  
  699.   char tmpname[256];
  700.  
  701.   mpwify_filename (filename, tmpname);
  702.   return open (tmpname, arg2);
  703. }
  704.  
  705. int
  706. mpw_access (char *filename, unsigned int cmd)
  707. {
  708. #undef access
  709.  
  710.   int rslt, errnum = 0;
  711.   struct stat st;
  712.   char tmpname[256];
  713.  
  714.   mpwify_filename (filename, tmpname);
  715.   if (DebugPI)
  716.     fprintf (stderr, "# mpw_access (%s, %d)", tmpname, cmd);
  717.   if (cmd & R_OK || cmd & X_OK)
  718.     {
  719.       rslt = stat (tmpname, &st);
  720.       errnum = errno;
  721.       if (rslt >= 0)
  722.     {
  723.       if (((st.st_mode & 004 == 0) && (cmd & R_OK))
  724.           || ((st.st_mode & 002 == 0) && (cmd & W_OK))
  725.           || ((st.st_mode & 001 == 0) && (cmd & X_OK)))
  726.         {
  727.           rslt = -1;
  728.           errnum = EACCES;
  729.         }
  730.     }
  731.     }
  732.   if (DebugPI)
  733.     {
  734.       fprintf (stderr, " -> %d", rslt);
  735.       if (rslt != 0)
  736.     fprintf (stderr, " (errno is %d)", errnum);
  737.       fprintf (stderr, "\n");
  738.     }
  739.   if (rslt != 0)
  740.     errno = errnum;
  741.   return rslt;
  742. }
  743.  
  744. chdir ()
  745. {
  746.   errno = ENOSYS;
  747.   return (-1);
  748. }
  749.  
  750. char *
  751. getcwd (char *buf, int size)
  752. {
  753.   if (buf == NULL)
  754.     buf = (char *) malloc (size);
  755.   strcpy(buf, ":");
  756.   return buf;
  757. }
  758.  
  759. /* This is a hack to get control in an MPW tool before it crashes the
  760.    machine.  */
  761.  
  762. mpw_special_init (name)
  763.      char *name;
  764. {
  765.   if (strstr (name, "DEBUG"))
  766.     DebugStr("\pat beginning of program");
  767. }
  768.  
  769. static int current_umask;
  770.  
  771. int
  772. umask(int mask)
  773. {
  774.   int oldmask = current_umask;
  775.  
  776.   current_umask = mask;
  777.   return oldmask;
  778. }
  779.  
  780. #ifdef IN_GCC
  781.  
  782. #define NEED_sys_errlist
  783.  
  784. /* Extended support for using errno values.
  785.    Copyright (C) 1992 Free Software Foundation, Inc.
  786.    Written by Fred Fish.  fnf@cygnus.com
  787.  
  788. This file is part of the libiberty library.
  789. Libiberty is free software; you can redistribute it and/or
  790. modify it under the terms of the GNU Library General Public
  791. License as published by the Free Software Foundation; either
  792. version 2 of the License, or (at your option) any later version.
  793.  
  794. Libiberty is distributed in the hope that it will be useful,
  795. but WITHOUT ANY WARRANTY; without even the implied warranty of
  796. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  797. Library General Public License for more details.
  798.  
  799. You should have received a copy of the GNU Library General Public
  800. License along with libiberty; see the file COPYING.LIB.  If
  801. not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  802. Boston, MA 02111-1307, USA.  */
  803.  
  804. #ifndef NEED_sys_errlist
  805. /* Note that errno.h (not sure what OS) or stdio.h (BSD 4.4, at least)
  806.    might declare sys_errlist in a way that the compiler might consider
  807.    incompatible with our later declaration, perhaps by using const
  808.    attributes.  So we hide the declaration in errno.h (if any) using a
  809.    macro. */
  810. #define sys_errlist sys_errlist__
  811. #endif
  812.  
  813. #include <stdio.h>
  814. #include <errno.h>
  815.  
  816. #ifndef NEED_sys_errlist
  817. #undef sys_errlist
  818. #endif
  819.  
  820. /*  Routines imported from standard C runtime libraries. */
  821.  
  822. #ifdef __STDC__
  823. #include <stddef.h>
  824. extern void *malloc (size_t size);                /* 4.10.3.3 */
  825. extern void *memset (void *s, int c, size_t n);            /* 4.11.6.1 */
  826. #else    /* !__STDC__ */
  827. #ifndef const
  828. #define const
  829. #endif
  830. extern char *malloc ();        /* Standard memory allocater */
  831. extern char *memset ();
  832. #endif    /* __STDC__ */
  833.  
  834. #ifndef MAX
  835. #  define MAX(a,b) ((a) > (b) ? (a) : (b))
  836. #endif
  837.  
  838. /* Translation table for errno values.  See intro(2) in most UNIX systems
  839.    Programmers Reference Manuals.
  840.  
  841.    Note that this table is generally only accessed when it is used at runtime
  842.    to initialize errno name and message tables that are indexed by errno
  843.    value.
  844.  
  845.    Not all of these errnos will exist on all systems.  This table is the only
  846.    thing that should have to be updated as new error numbers are introduced.
  847.    It's sort of ugly, but at least its portable. */
  848.  
  849. struct error_info
  850. {
  851.   int value;        /* The numeric value from <errno.h> */
  852.   const char *name;    /* The equivalent symbolic value */
  853. #ifdef NEED_sys_errlist
  854.   const char *msg;    /* Short message about this value */
  855. #endif
  856. };
  857.  
  858. #ifdef NEED_sys_errlist
  859. #   define ENTRY(value, name, msg)    {value, name, msg}
  860. #else
  861. #   define ENTRY(value, name, msg)    {value, name}
  862. #endif
  863.  
  864. static const struct error_info error_table[] =
  865. {
  866. #if defined (EPERM)
  867.   ENTRY(EPERM, "EPERM", "Not owner"),
  868. #endif
  869. #if defined (ENOENT)
  870.   ENTRY(ENOENT, "ENOENT", "No such file or directory"),
  871. #endif
  872. #if defined (ESRCH)
  873.   ENTRY(ESRCH, "ESRCH", "No such process"),
  874. #endif
  875. #if defined (EINTR)
  876.   ENTRY(EINTR, "EINTR", "Interrupted system call"),
  877. #endif
  878. #if defined (EIO)
  879.   ENTRY(EIO, "EIO", "I/O error"),
  880. #endif
  881. #if defined (ENXIO)
  882.   ENTRY(ENXIO, "ENXIO", "No such device or address"),
  883. #endif
  884. #if defined (E2BIG)
  885.   ENTRY(E2BIG, "E2BIG", "Arg list too long"),
  886. #endif
  887. #if defined (ENOEXEC)
  888.   ENTRY(ENOEXEC, "ENOEXEC", "Exec format error"),
  889. #endif
  890. #if defined (EBADF)
  891.   ENTRY(EBADF, "EBADF", "Bad file number"),
  892. #endif
  893. #if defined (ECHILD)
  894.   ENTRY(ECHILD, "ECHILD", "No child processes"),
  895. #endif
  896. #if defined (EWOULDBLOCK)    /* Put before EAGAIN, sometimes aliased */
  897.   ENTRY(EWOULDBLOCK, "EWOULDBLOCK", "Operation would block"),
  898. #endif
  899. #if defined (EAGAIN)
  900.   ENTRY(EAGAIN, "EAGAIN", "No more processes"),
  901. #endif
  902. #if defined (ENOMEM)
  903.   ENTRY(ENOMEM, "ENOMEM", "Not enough space"),
  904. #endif
  905. #if defined (EACCES)
  906.   ENTRY(EACCES, "EACCES", "Permission denied"),
  907. #endif
  908. #if defined (EFAULT)
  909.   ENTRY(EFAULT, "EFAULT", "Bad address"),
  910. #endif
  911. #if defined (ENOTBLK)
  912.   ENTRY(ENOTBLK, "ENOTBLK", "Block device required"),
  913. #endif
  914. #if defined (EBUSY)
  915.   ENTRY(EBUSY, "EBUSY", "Device busy"),
  916. #endif
  917. #if defined (EEXIST)
  918.   ENTRY(EEXIST, "EEXIST", "File exists"),
  919. #endif
  920. #if defined (EXDEV)
  921.   ENTRY(EXDEV, "EXDEV", "Cross-device link"),
  922. #endif
  923. #if defined (ENODEV)
  924.   ENTRY(ENODEV, "ENODEV", "No such device"),
  925. #endif
  926. #if defined (ENOTDIR)
  927.   ENTRY(ENOTDIR, "ENOTDIR", "Not a directory"),
  928. #endif
  929. #if defined (EISDIR)
  930.   ENTRY(EISDIR, "EISDIR", "Is a directory"),
  931. #endif
  932. #if defined (EINVAL)
  933.   ENTRY(EINVAL, "EINVAL", "Invalid argument"),
  934. #endif
  935. #if defined (ENFILE)
  936.   ENTRY(ENFILE, "ENFILE", "File table overflow"),
  937. #endif
  938. #if defined (EMFILE)
  939.   ENTRY(EMFILE, "EMFILE", "Too many open files"),
  940. #endif
  941. #if defined (ENOTTY)
  942.   ENTRY(ENOTTY, "ENOTTY", "Not a typewriter"),
  943. #endif
  944. #if defined (ETXTBSY)
  945.   ENTRY(ETXTBSY, "ETXTBSY", "Text file busy"),
  946. #endif
  947. #if defined (EFBIG)
  948.   ENTRY(EFBIG, "EFBIG", "File too large"),
  949. #endif
  950. #if defined (ENOSPC)
  951.   ENTRY(ENOSPC, "ENOSPC", "No space left on device"),
  952. #endif
  953. #if defined (ESPIPE)
  954.   ENTRY(ESPIPE, "ESPIPE", "Illegal seek"),
  955. #endif
  956. #if defined (EROFS)
  957.   ENTRY(EROFS, "EROFS", "Read-only file system"),
  958. #endif
  959. #if defined (EMLINK)
  960.   ENTRY(EMLINK, "EMLINK", "Too many links"),
  961. #endif
  962. #if defined (EPIPE)
  963.   ENTRY(EPIPE, "EPIPE", "Broken pipe"),
  964. #endif
  965. #if defined (EDOM)
  966.   ENTRY(EDOM, "EDOM", "Math argument out of domain of func"),
  967. #endif
  968. #if defined (ERANGE)
  969.   ENTRY(ERANGE, "ERANGE", "Math result not representable"),
  970. #endif
  971. #if defined (ENOMSG)
  972.   ENTRY(ENOMSG, "ENOMSG", "No message of desired type"),
  973. #endif
  974. #if defined (EIDRM)
  975.   ENTRY(EIDRM, "EIDRM", "Identifier removed"),
  976. #endif
  977. #if defined (ECHRNG)
  978.   ENTRY(ECHRNG, "ECHRNG", "Channel number out of range"),
  979. #endif
  980. #if defined (EL2NSYNC)
  981.   ENTRY(EL2NSYNC, "EL2NSYNC", "Level 2 not synchronized"),
  982. #endif
  983. #if defined (EL3HLT)
  984.   ENTRY(EL3HLT, "EL3HLT", "Level 3 halted"),
  985. #endif
  986. #if defined (EL3RST)
  987.   ENTRY(EL3RST, "EL3RST", "Level 3 reset"),
  988. #endif
  989. #if defined (ELNRNG)
  990.   ENTRY(ELNRNG, "ELNRNG", "Link number out of range"),
  991. #endif
  992. #if defined (EUNATCH)
  993.   ENTRY(EUNATCH, "EUNATCH", "Protocol driver not attached"),
  994. #endif
  995. #if defined (ENOCSI)
  996.   ENTRY(ENOCSI, "ENOCSI", "No CSI structure available"),
  997. #endif
  998. #if defined (EL2HLT)
  999.   ENTRY(EL2HLT, "EL2HLT", "Level 2 halted"),
  1000. #endif
  1001. #if defined (EDEADLK)
  1002.   ENTRY(EDEADLK, "EDEADLK", "Deadlock condition"),
  1003. #endif
  1004. #if defined (ENOLCK)
  1005.   ENTRY(ENOLCK, "ENOLCK", "No record locks available"),
  1006. #endif
  1007. #if defined (EBADE)
  1008.   ENTRY(EBADE, "EBADE", "Invalid exchange"),
  1009. #endif
  1010. #if defined (EBADR)
  1011.   ENTRY(EBADR, "EBADR", "Invalid request descriptor"),
  1012. #endif
  1013. #if defined (EXFULL)
  1014.   ENTRY(EXFULL, "EXFULL", "Exchange full"),
  1015. #endif
  1016. #if defined (ENOANO)
  1017.   ENTRY(ENOANO, "ENOANO", "No anode"),
  1018. #endif
  1019. #if defined (EBADRQC)
  1020.   ENTRY(EBADRQC, "EBADRQC", "Invalid request code"),
  1021. #endif
  1022. #if defined (EBADSLT)
  1023.   ENTRY(EBADSLT, "EBADSLT", "Invalid slot"),
  1024. #endif
  1025. #if defined (EDEADLOCK)
  1026.   ENTRY(EDEADLOCK, "EDEADLOCK", "File locking deadlock error"),
  1027. #endif
  1028. #if defined (EBFONT)
  1029.   ENTRY(EBFONT, "EBFONT", "Bad font file format"),
  1030. #endif
  1031. #if defined (ENOSTR)
  1032.   ENTRY(ENOSTR, "ENOSTR", "Device not a stream"),
  1033. #endif
  1034. #if defined (ENODATA)
  1035.   ENTRY(ENODATA, "ENODATA", "No data available"),
  1036. #endif
  1037. #if defined (ETIME)
  1038.   ENTRY(ETIME, "ETIME", "Timer expired"),
  1039. #endif
  1040. #if defined (ENOSR)
  1041.   ENTRY(ENOSR, "ENOSR", "Out of streams resources"),
  1042. #endif
  1043. #if defined (ENONET)
  1044.   ENTRY(ENONET, "ENONET", "Machine is not on the network"),
  1045. #endif
  1046. #if defined (ENOPKG)
  1047.   ENTRY(ENOPKG, "ENOPKG", "Package not installed"),
  1048. #endif
  1049. #if defined (EREMOTE)
  1050.   ENTRY(EREMOTE, "EREMOTE", "Object is remote"),
  1051. #endif
  1052. #if defined (ENOLINK)
  1053.   ENTRY(ENOLINK, "ENOLINK", "Link has been severed"),
  1054. #endif
  1055. #if defined (EADV)
  1056.   ENTRY(EADV, "EADV", "Advertise error"),
  1057. #endif
  1058. #if defined (ESRMNT)
  1059.   ENTRY(ESRMNT, "ESRMNT", "Srmount error"),
  1060. #endif
  1061. #if defined (ECOMM)
  1062.   ENTRY(ECOMM, "ECOMM", "Communication error on send"),
  1063. #endif
  1064. #if defined (EPROTO)
  1065.   ENTRY(EPROTO, "EPROTO", "Protocol error"),
  1066. #endif
  1067. #if defined (EMULTIHOP)
  1068.   ENTRY(EMULTIHOP, "EMULTIHOP", "Multihop attempted"),
  1069. #endif
  1070. #if defined (EDOTDOT)
  1071.   ENTRY(EDOTDOT, "EDOTDOT", "RFS specific error"),
  1072. #endif
  1073. #if defined (EBADMSG)
  1074.   ENTRY(EBADMSG, "EBADMSG", "Not a data message"),
  1075. #endif
  1076. #if defined (ENAMETOOLONG)
  1077.   ENTRY(ENAMETOOLONG, "ENAMETOOLONG", "File name too long"),
  1078. #endif
  1079. #if defined (EOVERFLOW)
  1080.   ENTRY(EOVERFLOW, "EOVERFLOW", "Value too large for defined data type"),
  1081. #endif
  1082. #if defined (ENOTUNIQ)
  1083.   ENTRY(ENOTUNIQ, "ENOTUNIQ", "Name not unique on network"),
  1084. #endif
  1085. #if defined (EBADFD)
  1086.   ENTRY(EBADFD, "EBADFD", "File descriptor in bad state"),
  1087. #endif
  1088. #if defined (EREMCHG)
  1089.   ENTRY(EREMCHG, "EREMCHG", "Remote address changed"),
  1090. #endif
  1091. #if defined (ELIBACC)
  1092.   ENTRY(ELIBACC, "ELIBACC", "Can not access a needed shared library"),
  1093. #endif
  1094. #if defined (ELIBBAD)
  1095.   ENTRY(ELIBBAD, "ELIBBAD", "Accessing a corrupted shared library"),
  1096. #endif
  1097. #if defined (ELIBSCN)
  1098.   ENTRY(ELIBSCN, "ELIBSCN", ".lib section in a.out corrupted"),
  1099. #endif
  1100. #if defined (ELIBMAX)
  1101.   ENTRY(ELIBMAX, "ELIBMAX", "Attempting to link in too many shared libraries"),
  1102. #endif
  1103. #if defined (ELIBEXEC)
  1104.   ENTRY(ELIBEXEC, "ELIBEXEC", "Cannot exec a shared library directly"),
  1105. #endif
  1106. #if defined (EILSEQ)
  1107.   ENTRY(EILSEQ, "EILSEQ", "Illegal byte sequence"),
  1108. #endif
  1109. #if defined (ENOSYS)
  1110.   ENTRY(ENOSYS, "ENOSYS", "Operation not applicable"),
  1111. #endif
  1112. #if defined (ELOOP)
  1113.   ENTRY(ELOOP, "ELOOP", "Too many symbolic links encountered"),
  1114. #endif
  1115. #if defined (ERESTART)
  1116.   ENTRY(ERESTART, "ERESTART", "Interrupted system call should be restarted"),
  1117. #endif
  1118. #if defined (ESTRPIPE)
  1119.   ENTRY(ESTRPIPE, "ESTRPIPE", "Streams pipe error"),
  1120. #endif
  1121. #if defined (ENOTEMPTY)
  1122.   ENTRY(ENOTEMPTY, "ENOTEMPTY", "Directory not empty"),
  1123. #endif
  1124. #if defined (EUSERS)
  1125.   ENTRY(EUSERS, "EUSERS", "Too many users"),
  1126. #endif
  1127. #if defined (ENOTSOCK)
  1128.   ENTRY(ENOTSOCK, "ENOTSOCK", "Socket operation on non-socket"),
  1129. #endif
  1130. #if defined (EDESTADDRREQ)
  1131.   ENTRY(EDESTADDRREQ, "EDESTADDRREQ", "Destination address required"),
  1132. #endif
  1133. #if defined (EMSGSIZE)
  1134.   ENTRY(EMSGSIZE, "EMSGSIZE", "Message too long"),
  1135. #endif
  1136. #if defined (EPROTOTYPE)
  1137.   ENTRY(EPROTOTYPE, "EPROTOTYPE", "Protocol wrong type for socket"),
  1138. #endif
  1139. #if defined (ENOPROTOOPT)
  1140.   ENTRY(ENOPROTOOPT, "ENOPROTOOPT", "Protocol not available"),
  1141. #endif
  1142. #if defined (EPROTONOSUPPORT)
  1143.   ENTRY(EPROTONOSUPPORT, "EPROTONOSUPPORT", "Protocol not supported"),
  1144. #endif
  1145. #if defined (ESOCKTNOSUPPORT)
  1146.   ENTRY(ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT", "Socket type not supported"),
  1147. #endif
  1148. #if defined (EOPNOTSUPP)
  1149.   ENTRY(EOPNOTSUPP, "EOPNOTSUPP", "Operation not supported on transport endpoint"),
  1150. #endif
  1151. #if defined (EPFNOSUPPORT)
  1152.   ENTRY(EPFNOSUPPORT, "EPFNOSUPPORT", "Protocol family not supported"),
  1153. #endif
  1154. #if defined (EAFNOSUPPORT)
  1155.   ENTRY(EAFNOSUPPORT, "EAFNOSUPPORT", "Address family not supported by protocol"),
  1156. #endif
  1157. #if defined (EADDRINUSE)
  1158.   ENTRY(EADDRINUSE, "EADDRINUSE", "Address already in use"),
  1159. #endif
  1160. #if defined (EADDRNOTAVAIL)
  1161.   ENTRY(EADDRNOTAVAIL, "EADDRNOTAVAIL","Cannot assign requested address"),
  1162. #endif
  1163. #if defined (ENETDOWN)
  1164.   ENTRY(ENETDOWN, "ENETDOWN", "Network is down"),
  1165. #endif
  1166. #if defined (ENETUNREACH)
  1167.   ENTRY(ENETUNREACH, "ENETUNREACH", "Network is unreachable"),
  1168. #endif
  1169. #if defined (ENETRESET)
  1170.   ENTRY(ENETRESET, "ENETRESET", "Network dropped connection because of reset"),
  1171. #endif
  1172. #if defined (ECONNABORTED)
  1173.   ENTRY(ECONNABORTED, "ECONNABORTED", "Software caused connection abort"),
  1174. #endif
  1175. #if defined (ECONNRESET)
  1176.   ENTRY(ECONNRESET, "ECONNRESET", "Connection reset by peer"),
  1177. #endif
  1178. #if defined (ENOBUFS)
  1179.   ENTRY(ENOBUFS, "ENOBUFS", "No buffer space available"),
  1180. #endif
  1181. #if defined (EISCONN)
  1182.   ENTRY(EISCONN, "EISCONN", "Transport endpoint is already connected"),
  1183. #endif
  1184. #if defined (ENOTCONN)
  1185.   ENTRY(ENOTCONN, "ENOTCONN", "Transport endpoint is not connected"),
  1186. #endif
  1187. #if defined (ESHUTDOWN)
  1188.   ENTRY(ESHUTDOWN, "ESHUTDOWN", "Cannot send after transport endpoint shutdown"),
  1189. #endif
  1190. #if defined (ETOOMANYREFS)
  1191.   ENTRY(ETOOMANYREFS, "ETOOMANYREFS", "Too many references: cannot splice"),
  1192. #endif
  1193. #if defined (ETIMEDOUT)
  1194.   ENTRY(ETIMEDOUT, "ETIMEDOUT", "Connection timed out"),
  1195. #endif
  1196. #if defined (ECONNREFUSED)
  1197.   ENTRY(ECONNREFUSED, "ECONNREFUSED", "Connection refused"),
  1198. #endif
  1199. #if defined (EHOSTDOWN)
  1200.   ENTRY(EHOSTDOWN, "EHOSTDOWN", "Host is down"),
  1201. #endif
  1202. #if defined (EHOSTUNREACH)
  1203.   ENTRY(EHOSTUNREACH, "EHOSTUNREACH", "No route to host"),
  1204. #endif
  1205. #if defined (EALREADY)
  1206.   ENTRY(EALREADY, "EALREADY", "Operation already in progress"),
  1207. #endif
  1208. #if defined (EINPROGRESS)
  1209.   ENTRY(EINPROGRESS, "EINPROGRESS", "Operation now in progress"),
  1210. #endif
  1211. #if defined (ESTALE)
  1212.   ENTRY(ESTALE, "ESTALE", "Stale NFS file handle"),
  1213. #endif
  1214. #if defined (EUCLEAN)
  1215.   ENTRY(EUCLEAN, "EUCLEAN", "Structure needs cleaning"),
  1216. #endif
  1217. #if defined (ENOTNAM)
  1218.   ENTRY(ENOTNAM, "ENOTNAM", "Not a XENIX named type file"),
  1219. #endif
  1220. #if defined (ENAVAIL)
  1221.   ENTRY(ENAVAIL, "ENAVAIL", "No XENIX semaphores available"),
  1222. #endif
  1223. #if defined (EISNAM)
  1224.   ENTRY(EISNAM, "EISNAM", "Is a named type file"),
  1225. #endif
  1226. #if defined (EREMOTEIO)
  1227.   ENTRY(EREMOTEIO, "EREMOTEIO", "Remote I/O error"),
  1228. #endif
  1229.   ENTRY(0, NULL, NULL)
  1230. };
  1231.  
  1232. /* Translation table allocated and initialized at runtime.  Indexed by the
  1233.    errno value to find the equivalent symbolic value. */
  1234.  
  1235. static const char **error_names;
  1236. static int num_error_names = 0;
  1237.  
  1238. /* Translation table allocated and initialized at runtime, if it does not
  1239.    already exist in the host environment.  Indexed by the errno value to find
  1240.    the descriptive string.
  1241.  
  1242.    We don't export it for use in other modules because even though it has the
  1243.    same name, it differs from other implementations in that it is dynamically
  1244.    initialized rather than statically initialized. */
  1245.  
  1246. #ifdef NEED_sys_errlist
  1247.  
  1248. int sys_nerr;
  1249. const char **sys_errlist;
  1250.  
  1251. #else
  1252.  
  1253. extern int sys_nerr;
  1254. extern char *sys_errlist[];
  1255.  
  1256. #endif
  1257.  
  1258.  
  1259. /*
  1260.  
  1261. NAME
  1262.  
  1263.     init_error_tables -- initialize the name and message tables
  1264.  
  1265. SYNOPSIS
  1266.  
  1267.     static void init_error_tables ();
  1268.  
  1269. DESCRIPTION
  1270.  
  1271.     Using the error_table, which is initialized at compile time, generate
  1272.     the error_names and the sys_errlist (if needed) tables, which are
  1273.     indexed at runtime by a specific errno value.
  1274.  
  1275. BUGS
  1276.  
  1277.     The initialization of the tables may fail under low memory conditions,
  1278.     in which case we don't do anything particularly useful, but we don't
  1279.     bomb either.  Who knows, it might succeed at a later point if we free
  1280.     some memory in the meantime.  In any case, the other routines know
  1281.     how to deal with lack of a table after trying to initialize it.  This
  1282.     may or may not be considered to be a bug, that we don't specifically
  1283.     warn about this particular failure mode.
  1284.  
  1285. */
  1286.  
  1287. static void
  1288. init_error_tables ()
  1289. {
  1290.   const struct error_info *eip;
  1291.   int nbytes;
  1292.  
  1293.   /* If we haven't already scanned the error_table once to find the maximum
  1294.      errno value, then go find it now. */
  1295.  
  1296.   if (num_error_names == 0)
  1297.     {
  1298.       for (eip = error_table; eip -> name != NULL; eip++)
  1299.     {
  1300.       if (eip -> value >= num_error_names)
  1301.         {
  1302.           num_error_names = eip -> value + 1;
  1303.         }
  1304.     }
  1305.     }
  1306.  
  1307.   /* Now attempt to allocate the error_names table, zero it out, and then
  1308.      initialize it from the statically initialized error_table. */
  1309.  
  1310.   if (error_names == NULL)
  1311.     {
  1312.       nbytes = num_error_names * sizeof (char *);
  1313.       if ((error_names = (const char **) malloc (nbytes)) != NULL)
  1314.     {
  1315.       memset (error_names, 0, nbytes);
  1316.       for (eip = error_table; eip -> name != NULL; eip++)
  1317.         {
  1318.           error_names[eip -> value] = eip -> name;
  1319.         }
  1320.     }
  1321.     }
  1322.  
  1323. #ifdef NEED_sys_errlist
  1324.  
  1325.   /* Now attempt to allocate the sys_errlist table, zero it out, and then
  1326.      initialize it from the statically initialized error_table. */
  1327.  
  1328.   if (sys_errlist == NULL)
  1329.     {
  1330.       nbytes = num_error_names * sizeof (char *);
  1331.       if ((sys_errlist = (const char **) malloc (nbytes)) != NULL)
  1332.     {
  1333.       memset (sys_errlist, 0, nbytes);
  1334.       sys_nerr = num_error_names;
  1335.       for (eip = error_table; eip -> name != NULL; eip++)
  1336.         {
  1337.           sys_errlist[eip -> value] = eip -> msg;
  1338.         }
  1339.     }
  1340.     }
  1341.  
  1342. #endif
  1343.  
  1344. }
  1345.  
  1346. /*
  1347.  
  1348. NAME
  1349.  
  1350.     errno_max -- return the max errno value
  1351.  
  1352. SYNOPSIS
  1353.  
  1354.     int errno_max ();
  1355.  
  1356. DESCRIPTION
  1357.  
  1358.     Returns the maximum errno value for which a corresponding symbolic
  1359.     name or message is available.  Note that in the case where
  1360.     we use the sys_errlist supplied by the system, it is possible for
  1361.     there to be more symbolic names than messages, or vice versa.
  1362.     In fact, the manual page for perror(3C) explicitly warns that one
  1363.     should check the size of the table (sys_nerr) before indexing it,
  1364.     since new error codes may be added to the system before they are
  1365.     added to the table.  Thus sys_nerr might be smaller than value
  1366.     implied by the largest errno value defined in <errno.h>.
  1367.  
  1368.     We return the maximum value that can be used to obtain a meaningful
  1369.     symbolic name or message.
  1370.  
  1371. */
  1372.  
  1373. int
  1374. errno_max ()
  1375. {
  1376.   int maxsize;
  1377.  
  1378.   if (error_names == NULL)
  1379.     {
  1380.       init_error_tables ();
  1381.     }
  1382.   maxsize = MAX (sys_nerr, num_error_names);
  1383.   return (maxsize - 1);
  1384. }
  1385.  
  1386. #ifdef NEED_strerror
  1387.  
  1388. /*
  1389.  
  1390. NAME
  1391.  
  1392.     strerror -- map an error number to an error message string
  1393.  
  1394. SYNOPSIS
  1395.  
  1396.     char *strerror (int errnoval)
  1397.  
  1398. DESCRIPTION
  1399.  
  1400.     Maps an errno number to an error message string, the contents of
  1401.     which are implementation defined.  On systems which have the external
  1402.     variables sys_nerr and sys_errlist, these strings will be the same
  1403.     as the ones used by perror().
  1404.  
  1405.     If the supplied error number is within the valid range of indices
  1406.     for the sys_errlist, but no message is available for the particular
  1407.     error number, then returns the string "Error NUM", where NUM is the
  1408.     error number.
  1409.  
  1410.     If the supplied error number is not a valid index into sys_errlist,
  1411.     returns NULL.
  1412.  
  1413.     The returned string is only guaranteed to be valid only until the
  1414.     next call to strerror.
  1415.  
  1416. */
  1417.  
  1418. char *
  1419. strerror (errnoval)
  1420.   int errnoval;
  1421. {
  1422.   char *msg;
  1423.   static char buf[32];
  1424.  
  1425. #ifdef NEED_sys_errlist
  1426.  
  1427.   if (error_names == NULL)
  1428.     {
  1429.       init_error_tables ();
  1430.     }
  1431.  
  1432. #endif
  1433.  
  1434.   if ((errnoval < 0) || (errnoval >= sys_nerr))
  1435.     {
  1436.       /* Out of range, just return NULL */
  1437.       msg = NULL;
  1438.     }
  1439.   else if ((sys_errlist == NULL) || (sys_errlist[errnoval] == NULL))
  1440.     {
  1441.       /* In range, but no sys_errlist or no entry at this index. */
  1442.       sprintf (buf, "Error %d", errnoval);
  1443.       msg = buf;
  1444.     }
  1445.   else
  1446.     {
  1447.       /* In range, and a valid message.  Just return the message. */
  1448.       msg = (char *) sys_errlist[errnoval];
  1449.     }
  1450.   
  1451.   return (msg);
  1452. }
  1453.  
  1454. #endif    /* NEED_strerror */
  1455.  
  1456.  
  1457. /*
  1458.  
  1459. NAME
  1460.  
  1461.     strerrno -- map an error number to a symbolic name string
  1462.  
  1463. SYNOPSIS
  1464.  
  1465.     const char *strerrno (int errnoval)
  1466.  
  1467. DESCRIPTION
  1468.  
  1469.     Given an error number returned from a system call (typically
  1470.     returned in errno), returns a pointer to a string containing the
  1471.     symbolic name of that error number, as found in <errno.h>.
  1472.  
  1473.     If the supplied error number is within the valid range of indices
  1474.     for symbolic names, but no name is available for the particular
  1475.     error number, then returns the string "Error NUM", where NUM is
  1476.     the error number.
  1477.  
  1478.     If the supplied error number is not within the range of valid
  1479.     indices, then returns NULL.
  1480.  
  1481. BUGS
  1482.  
  1483.     The contents of the location pointed to are only guaranteed to be
  1484.     valid until the next call to strerrno.
  1485.  
  1486. */
  1487.  
  1488. const char *
  1489. strerrno (errnoval)
  1490.   int errnoval;
  1491. {
  1492.   const char *name;
  1493.   static char buf[32];
  1494.  
  1495.   if (error_names == NULL)
  1496.     {
  1497.       init_error_tables ();
  1498.     }
  1499.  
  1500.   if ((errnoval < 0) || (errnoval >= num_error_names))
  1501.     {
  1502.       /* Out of range, just return NULL */
  1503.       name = NULL;
  1504.     }
  1505.   else if ((error_names == NULL) || (error_names[errnoval] == NULL))
  1506.     {
  1507.       /* In range, but no error_names or no entry at this index. */
  1508.       sprintf (buf, "Error %d", errnoval);
  1509.       name = (const char *) buf;
  1510.     }
  1511.   else
  1512.     {
  1513.       /* In range, and a valid name.  Just return the name. */
  1514.       name = error_names[errnoval];
  1515.     }
  1516.  
  1517.   return (name);
  1518. }
  1519.  
  1520. /*
  1521.  
  1522. NAME
  1523.  
  1524.     strtoerrno -- map a symbolic errno name to a numeric value
  1525.  
  1526. SYNOPSIS
  1527.  
  1528.     int strtoerrno (char *name)
  1529.  
  1530. DESCRIPTION
  1531.  
  1532.     Given the symbolic name of a error number, map it to an errno value.
  1533.     If no translation is found, returns 0.
  1534.  
  1535. */
  1536.  
  1537. int
  1538. strtoerrno (name)
  1539.      const char *name;
  1540. {
  1541.   int errnoval = 0;
  1542.  
  1543.   if (name != NULL)
  1544.     {
  1545.       if (error_names == NULL)
  1546.     {
  1547.       init_error_tables ();
  1548.     }
  1549.       for (errnoval = 0; errnoval < num_error_names; errnoval++)
  1550.     {
  1551.       if ((error_names[errnoval] != NULL) &&
  1552.           (strcmp (name, error_names[errnoval]) == 0))
  1553.         {
  1554.           break;
  1555.         }
  1556.     }
  1557.       if (errnoval == num_error_names)
  1558.     {
  1559.       errnoval = 0;
  1560.     }
  1561.     }
  1562.   return (errnoval);
  1563. }
  1564.  
  1565.  
  1566. /* A simple little main that does nothing but print all the errno translations
  1567.    if MAIN is defined and this file is compiled and linked. */
  1568.  
  1569. #ifdef MAIN
  1570.  
  1571. #include <stdio.h>
  1572.  
  1573. int
  1574. main ()
  1575. {
  1576.   int errn;
  1577.   int errnmax;
  1578.   const char *name;
  1579.   char *msg;
  1580.   char *strerror ();
  1581.  
  1582.   errnmax = errno_max ();
  1583.   printf ("%d entries in names table.\n", num_error_names);
  1584.   printf ("%d entries in messages table.\n", sys_nerr);
  1585.   printf ("%d is max useful index.\n", errnmax);
  1586.  
  1587.   /* Keep printing values until we get to the end of *both* tables, not
  1588.      *either* table.  Note that knowing the maximum useful index does *not*
  1589.      relieve us of the responsibility of testing the return pointer for
  1590.      NULL. */
  1591.  
  1592.   for (errn = 0; errn <= errnmax; errn++)
  1593.     {
  1594.       name = strerrno (errn);
  1595.       name = (name == NULL) ? "<NULL>" : name;
  1596.       msg = strerror (errn);
  1597.       msg = (msg == NULL) ? "<NULL>" : msg;
  1598.       printf ("%-4d%-18s%s\n", errn, name, msg);
  1599.     }
  1600.  
  1601.   return 0;
  1602. }
  1603.  
  1604. #endif
  1605.  
  1606. #endif
  1607.  
  1608. /* Cursor-spinning stuff that includes metering of spin rate and delays.  */
  1609.  
  1610. /* Nonzero when cursor spinning has been set up properly.  */
  1611.  
  1612. int cursor_inited;
  1613.  
  1614. /* Nonzero if spin should be measured and excessive delays reported.  */
  1615.  
  1616. int measure_spin;
  1617.  
  1618. /* Nonzero if spin histogram and rate data should be written out.  */
  1619.  
  1620. int dump_spin_data;
  1621.  
  1622. long warning_threshold = 400000;
  1623.  
  1624. long bucket_size = 1024;
  1625.  
  1626. long bucket_power = 10;
  1627.  
  1628. long numbuckets = 300;
  1629.  
  1630. int *delay_counts;
  1631.  
  1632. int overflow_count;
  1633.  
  1634. char *current_progress;
  1635.  
  1636. #ifdef MPW
  1637.  
  1638. /* Note the MPW-specific syntax here.  */
  1639.  
  1640. /* Also note that we're only collecting the low half of a 64-bit
  1641.    value, the other half being in A0.  This means that every 20
  1642.    minutes or so, a difference with the last value from here will
  1643.    be spectacularly wrong.  */
  1644.  
  1645. long Microseconds () = 0xa193;
  1646.  
  1647. #endif
  1648.  
  1649. static long last_microseconds;
  1650.  
  1651. static char *last_spin_file = "";
  1652.  
  1653. static int last_spin_line;
  1654.  
  1655. void
  1656. warn_if_spin_delay (char *file, int line)
  1657. {
  1658.   long diff, ix;
  1659.   long now = Microseconds();
  1660.  
  1661.   diff = now - last_microseconds;
  1662.  
  1663.   if (diff > warning_threshold)
  1664.     fprintf (stderr, "# %s: %ld.%06ld sec delay getting from %s:%d to %s:%d\n",
  1665.          (current_progress ? current_progress : ""),
  1666.          diff / 1000000, diff % 1000000,
  1667.          last_spin_file, last_spin_line, file, line);
  1668.   if (dump_spin_data)
  1669.     {
  1670.       if (diff >= 0)
  1671.     {
  1672.       ix = diff >> bucket_power;
  1673.       if (ix >= 0 && ix < numbuckets && delay_counts != NULL)
  1674.         ++delay_counts[ix];
  1675.       else
  1676.         ++overflow_count;
  1677.     }
  1678.       else
  1679.     fprintf (stderr, "raw diff is %ld (?)\n", diff);
  1680.     }
  1681. }
  1682.  
  1683. void
  1684. record_for_spin_delay (char *file, int line)
  1685. {
  1686.   last_microseconds = Microseconds();
  1687.   last_spin_file = file;
  1688.   last_spin_line = line;
  1689. }
  1690.  
  1691. void
  1692. mpw_start_progress (char *str, int n, char *file, int line)
  1693. {
  1694.   int i;
  1695.   char *measure, *threshold;
  1696.  
  1697.   if (!cursor_inited)
  1698.     {
  1699.       InitCursorCtl (nil);
  1700.       cursor_inited = 1;
  1701.       record_for_spin_delay (file, line);
  1702.       measure = getenv ("MEASURE_SPIN");
  1703.       if (measure != NULL && measure[0] != '\0')
  1704.     {
  1705.       measure_spin = 1;
  1706.       if (strcmp (measure, "all") == 0)
  1707.         dump_spin_data = 1;
  1708.     }
  1709.       threshold = getenv ("SPIN_WARN_THRESHOLD");
  1710.       if (threshold != NULL && threshold[0] != '\0')
  1711.     warning_threshold = atol (threshold);
  1712.       if (dump_spin_data)
  1713.     {
  1714.       if (delay_counts == NULL)
  1715.         delay_counts = (int *) malloc (numbuckets * sizeof (int));
  1716.       for (i = 0; i < numbuckets; ++i)
  1717.         delay_counts[i] = 0;
  1718.       overflow_count = 0;
  1719.     }
  1720.     }
  1721.   current_progress = str;
  1722.  
  1723.   mpw_special_init (str);
  1724. }
  1725.  
  1726. void
  1727. mpw_progress (int n)
  1728. {
  1729.   SpinCursor (32);
  1730. }
  1731.  
  1732. void
  1733. mpw_progress_measured (int n, char *file, int line)
  1734. {
  1735.   if (measure_spin)
  1736.     warn_if_spin_delay (file, line);
  1737.   SpinCursor (32);
  1738.   if (measure_spin)
  1739.     record_for_spin_delay (file, line);
  1740. }
  1741.  
  1742. void
  1743. mpw_end_progress (char *str, char *file, int line)
  1744. {
  1745.   long i, delay, count = 0, sum = 0, avgdelay, spinrate;
  1746.   long curpower = 0, curgroup = 0;
  1747.  
  1748.   /* Warn if it's been a while since the last spin.  */
  1749.   if (measure_spin)
  1750.     warn_if_spin_delay (file, line);
  1751.  
  1752.   /* Dump all the nonzero delay counts and an approximation of the delay.  */
  1753.   if (dump_spin_data && delay_counts != NULL)
  1754.     {
  1755.       for (i = 0; i < numbuckets; ++i)
  1756.     {
  1757.       delay = (i + 1) * bucket_size;
  1758.       sum += delay_counts[i] * (i + 1);
  1759.       count += delay_counts[i];
  1760.       if (delay <= (1 << curpower))
  1761.         {
  1762.           curgroup += delay_counts[i];
  1763.         }
  1764.       else
  1765.         {
  1766.           if (curgroup > 0)
  1767.         fprintf (stderr,
  1768.              "# %s: %d delays between %ld.%06ld and %ld.%06ld sec\n",
  1769.              (str ? str : ""),
  1770.              curgroup,
  1771.              (1 << curpower) / 1000000,
  1772.              (1 << curpower) % 1000000,
  1773.              (1 << (curpower + 1)) / 1000000,
  1774.              (1 << (curpower + 1)) % 1000000);
  1775.           ++curpower;
  1776.           curgroup = 0;
  1777.         }
  1778.     }
  1779.       if (count > 0)
  1780.     {
  1781.       avgdelay = (sum * bucket_size) / count;
  1782.       spinrate = 1000000 / avgdelay;
  1783.       fprintf (stderr, "# %s: Average spin rate is %d times/sec\n",
  1784.            (str ? str : ""), spinrate);
  1785.     }
  1786.     }
  1787. }
  1788.  
  1789. #ifdef PROGRESS_TEST
  1790.  
  1791. /* Test program.  */
  1792.  
  1793. main ()
  1794. {
  1795.   int i, j;
  1796.   double x = 1.0, y = 2.4;
  1797.   long start = Microseconds (), tm;
  1798.  
  1799.   START_PROGRESS ("hi", 0);
  1800.  
  1801.   for (i = 0; i < 1000; ++i)
  1802.     {
  1803.       PROGRESS (1);
  1804.  
  1805.       for (j = 0; j < (i * 100); ++j)
  1806.     {
  1807.       x += (x * y) / j;
  1808.     }
  1809.     }
  1810.   
  1811.   END_PROGRESS ("hi");
  1812.   
  1813.   tm = Microseconds () - start;
  1814.  
  1815.   printf ("Total time is %d.%d secs\n", tm / 1000000, tm % 1000000);
  1816. }
  1817.  
  1818. #endif
  1819.